package special_tree;

import compiler.CompilerException;

import code.CodeList;
import code.Opcode;
import lexer.Token;
import tree.DataType;
import tree.MyTree;
import tree.Tree;
import tree.Type;
import tree.TypingException;

public class BinOpTree extends MyTree {

	@Deprecated
	private Type typ;
	
	public BinOpTree(Token token, Tree... operands) {
		super(token, operands);
	}

	@Deprecated
	private boolean isTokenType(String ...strings ) {
		for (String s : strings) {
			if (s.equals(getToken().getType().getText())) {
				return true;
			}
		}
		return false;
	}
	@Deprecated
	private boolean isType(Type cuT, DataType ...dataTypes ) {
		for (DataType dt : dataTypes) {
			if (cuT.equals(new Type(dt,""))) {
				return true;
			}
		}
		return false;
	}
	
	/* (non-Javadoc)
	 * @see tree.MyTree#computeType()
	 */
	@Override
	@Deprecated
	public Type computeType() throws TypingException {
		Type currentType = this.expectSameType(getOperand(0), getOperand(1));
		typ = currentType;
		if (isType(currentType,DataType.INT, DataType.DOUBLE) && isTokenType("+","-","%","/","*")) {
			return currentType;
		}
		else if (isType(currentType,DataType.INT,DataType.DOUBLE,DataType.CHAR,DataType.BOOL)
				&& isTokenType("==","!=")) {
			typ = new Type(DataType.BOOL,"");
			return typ;
		}
		else if (isType(currentType, DataType.INT, DataType.DOUBLE, DataType.CHAR) &&
				isTokenType("<",">","<=",">=")) {
			typ = new Type(DataType.BOOL,"");
			return typ;
		}
		else if (isType(currentType, DataType.INT) && isTokenType("<<",">>")) {
			return currentType;
		}
		else if (isType(currentType, DataType.INT, DataType.BOOL) && isTokenType("&", "|")) {
			return currentType;
		}
		else if (isType(currentType, DataType.BOOL) && isTokenType("&&", "||", "^")) {
			return currentType;
		}
		throw new TypingException(getToken(), "Operator does not match with Typ "+currentType.getDataType().name());
	}

	/* (non-Javadoc)
	 * @see tree.MyTree#generateCode(code.CodeList)
	 */
	@Override
	@Deprecated
	public void generateCode(CodeList code) throws CompilerException {
		if (getToken().getType().getText().equals("&&")) {
			code.generateCode(Opcode.LDIC, 0);
			getOperand(1).generateCode(code);
			getOperand(0).generateCode(code);
			code.generateCode(Opcode.SEL);
		}
		else if (getToken().getType().getText().equals("||")) {
			getOperand(1).generateCode(code);
			code.generateCode(Opcode.LDIC, 1);
			getOperand(0).generateCode(code);
			code.generateCode(Opcode.SEL);
		}
		else {
			getOperand(1).generateCode(code);
			getOperand(0).generateCode(code);
			switch(getToken().getType()) {
			case PLUS:
				code.generateCode(Opcode.ADD);
				break;
			case MINUS:
				code.generateCode(Opcode.SUB);
				break;
			case MUL:
				code.generateCode(Opcode.MUL);
				break;
			case DIVORSLASH:
				if (this.typ.equals(new Type(DataType.INT, ""))) {
					code.generateCode(Opcode.GDIV);
				}
				else {
					code.generateCode(Opcode.DIV);
				}
				break;
			case MOD:
				code.generateCode(Opcode.MOD);
				break;
			case SHL:
				code.generateCode(Opcode.SHIFTL);
				break;
			case SHR:
				code.generateCode(Opcode.SHIFTR);
				break;
			case LT:
				code.generateCode(Opcode.LESS);
				break;
			case LE:
				code.generateCode(Opcode.LESSEQUAL);
				break;
			case GT:
				code.generateCode(Opcode.GREATER);
				break;
			case GE:
				code.generateCode(Opcode.GREATEREQUAL);
				break;
			case EQ:
				code.generateCode(Opcode.EQUAL);
				break;
			case NE:
				code.generateCode(Opcode.NOTEQUAL);
				break;
			case BITAND:
				code.generateCode(Opcode.AND);
				break;
			case BITOR:
				code.generateCode(Opcode.OR);
				break;
			case XOR:
				code.generateCode(Opcode.XOR);
				break;
			default:
				throw new CompilerException(getToken().getType().getText()+" : Unkonown Operation");	
			}
		}
	}

}
